'    Copyright 2008 Jan Molnar <jan.molnar@abds.de>
'
'    This file is part of JCQ.

'    JCQ is free software: you can redistribute it and/or modify
'    it under the terms of the GNU General Public License as published by
'    the Free Software Foundation, either version 2 of the License, or
'    (at your option) any later version.

'    JCQ is distributed in the hope that it will be useful,
'    but WITHOUT ANY WARRANTY; without even the implied warranty of
'    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'    GNU General Public License for more details.

'    You should have received a copy of the GNU General Public License
'    along with JCQ. If not, see <http://www.gnu.org/licenses/>.

Imports System.Linq
Imports System.ComponentModel
Imports System.Collections.ObjectModel
Imports System.Collections.Specialized

Public Class GroupViewModelCache
    Private Shared _Cache As New Dictionary(Of IcqInterface.Interfaces.IGroup, GroupViewModel)

    Public Shared Function GetViewModel(ByVal group As IcqInterface.Interfaces.IGroup) As GroupViewModel
        Dim vm As GroupViewModel

        SyncLock _Cache
            If _Cache.ContainsKey(group) Then
                vm = _Cache(group)
            Else
                vm = New GroupViewModel(group)
                _Cache.Add(group, vm)
            End If
        End SyncLock

        Return vm
    End Function
End Class

Public Class GroupViewModelCollectionBinding
    Inherits Core.NotifyingCollectionBinding(Of GroupViewModel)

    Public Sub New(ByVal source As INotifyCollectionChanged, ByVal target As ObservableCollection(Of GroupViewModel))
        MyBase.New(source, target)
    End Sub

    Protected Overrides Sub OnSourceChanged(ByVal sender As Object, ByVal e As NotifyCollectionChangedEventArgs)
        Select Case e.Action
            Case Specialized.NotifyCollectionChangedAction.Add
                TargetInsert(e.NewStartingIndex, GroupViewModelCache.GetViewModel(DirectCast(e.NewItems(0), IcqInterface.Interfaces.IGroup)))
            Case Specialized.NotifyCollectionChangedAction.Remove
                TargetRemove(GroupViewModelCache.GetViewModel(DirectCast(e.NewItems(0), IcqInterface.Interfaces.IGroup)))
            Case Specialized.NotifyCollectionChangedAction.Replace
                TargetItem(e.NewStartingIndex) = GroupViewModelCache.GetViewModel(DirectCast(e.NewItems(0), IcqInterface.Interfaces.IGroup))
            Case Specialized.NotifyCollectionChangedAction.Reset
                TargetClear()
            Case Specialized.NotifyCollectionChangedAction.Move
                TargetMove(e.OldStartingIndex, e.NewStartingIndex)
        End Select
    End Sub
End Class

Public Class GroupViewModel
    Inherits System.Windows.Threading.DispatcherObject
    Implements INotifyPropertyChanged

    Private _Model As IcqInterface.Interfaces.IGroup

    Private _Contacts As ObservableCollection(Of ContactViewModel)
    Private _ContactsBinding As ContactViewModelCollectionBinding
    Private _ContactsView As CollectionView

    Private _Groups As ObservableCollection(Of GroupViewModel)
    Private _GroupsView As CollectionView
    Private _GroupsBinding As GroupViewModelCollectionBinding

    Public Sub New(ByVal model As IcqInterface.Interfaces.IGroup)
        _Model = model

        AddHandler _Model.PropertyChanged, AddressOf HandlePropertyChanged
    End Sub

    Friend Sub OnContactPropertyChanged(ByVal sender As Object, ByVal e As ComponentModel.PropertyChangedEventArgs)
        Dim c As ContactViewModel = DirectCast(sender, ContactViewModel)

        If e.PropertyName = "StatusFlag" Or e.PropertyName = "Name" Then
            Dispatcher.BeginInvoke(Windows.Threading.DispatcherPriority.Background, New Action(AddressOf ContactsView.Refresh))
        End If
    End Sub

    Public ReadOnly Property Model() As IcqInterface.Interfaces.IGroup
        Get
            Return _Model
        End Get
    End Property

    Public ReadOnly Property Contacts() As ObservableCollection(Of ContactViewModel)
        Get
            If _Contacts Is Nothing Then
                SyncLock _Model.Contacts
                    _Contacts = New ObservableCollection(Of ContactViewModel)((From c In _Model.Contacts Select ContactViewModelCache.GetViewModel(c)).ToList)
                    _ContactsBinding = New ContactViewModelCollectionBinding(_Model.Contacts, _Contacts)
                End SyncLock
            End If

            Return _Contacts
        End Get
    End Property

    Public ReadOnly Property Groups() As ObservableCollection(Of GroupViewModel)
        Get
            If _Groups Is Nothing Then
                SyncLock _Model.Groups
                    _Groups = New ObservableCollection(Of GroupViewModel)((From g In _Model.Groups Select GroupViewModelCache.GetViewModel(g)).ToList)
                    _GroupsBinding = New GroupViewModelCollectionBinding(_Model.Groups, _Groups)
                End SyncLock
            End If

            Return _Groups
        End Get
    End Property

    Public ReadOnly Property GroupsView() As CollectionView
        Get
            If _GroupsView Is Nothing Then
                _GroupsView = DirectCast(CollectionViewSource.GetDefaultView(Groups), CollectionView)
                _GroupsView.SortDescriptions.Add(New SortDescription("Name", ListSortDirection.Ascending))
            End If

            Return _GroupsView
        End Get
    End Property

    Public ReadOnly Property ContactsView() As CollectionView
        Get
            If _ContactsView Is Nothing Then
                _ContactsView = DirectCast(CollectionViewSource.GetDefaultView(Contacts), CollectionView)

                _ContactsView.SortDescriptions.Add(New System.ComponentModel.SortDescription("StatusFlag", ComponentModel.ListSortDirection.Ascending))
                _ContactsView.SortDescriptions.Add(New System.ComponentModel.SortDescription("Name", ComponentModel.ListSortDirection.Ascending))
            End If

            Return _ContactsView
        End Get
    End Property

    Public ReadOnly Property Attributes() As System.Collections.Hashtable
        Get
            Return _Model.Attributes
        End Get
    End Property

    Public ReadOnly Property Identifier() As String
        Get
            Return _Model.Identifier
        End Get
    End Property

    Public ReadOnly Property Name() As String
        Get
            Return _Model.Name
        End Get
    End Property

    Protected Sub HandlePropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
        Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Normal, New Action(Of PropertyChangedEventArgs)(AddressOf OnPropertyChanged), e)
    End Sub

    Protected Sub OnPropertyChanged(ByVal e As System.ComponentModel.PropertyChangedEventArgs)
        RaiseEvent PropertyChanged(Me, e)
    End Sub

    'Protected Sub XO(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs)
    '    Debug.WriteLine(String.Format("Changed: {0}", e.PropertyName), "XO")
    'End Sub

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class